/*!
 * # 模块 JS:
 *  Users - 用户管理
 * 
 * # 描述:
 *  向系统管理人员提供用户的管理功能，包括为用户设置权限。
 * 
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

/*
 * @param {Object} $    jQuery 命名空间。
 * @param {Object} $$   pittypat 命名空间。
 * @param {Object} _mod 模块 Apps (应用与功能) 的命名空间。
 * 
 * 使用 pittypat.namespace('...') 以确保 _mod 命名空间是存在的。
 * 
 * 更多说明请参见：
 * https://www.pittypat.work/com/waln/pittypat/coding/help/index.html#js。
 */
(function ($, $$, _mod) {
    'use strict';

    $$.ui.msg = '...';
    /*
     * 为登录用户注册一个处理函数。
     * 由于没有为匿名用户注册处理函数，那么当发现用户尚未登录时，则会默认跳转到首页（登录页）。
     * 
     * 如果需要为匿名用户添加处理逻辑，应该使用如下格式的代码：
     * $$({
     *     authorized: function (_) {
     *         ...
     *     },
     *     anonymous: function (_) {
     *         // 跳转到自定义的登录页面
     *         window.location = '../../../../login.html';
     *     }
     * });
     * 
     * 如果需要自定义登录页面，则可能还需要添加 init 等处理函数。详细帮助请参见：
     * https://www.pittypat.work/com/waln/pittypat/ref/help/pittypat.js.html#pittypat。
     *
     * 参数 _ 的定义如下：
     * {
     *    user:  {Object},  // (只读)当前用户的用户信息
     *    app:   {Object},  // (只读)当前应用的命名空间，如果无法定位，则为 null
     *    mod:   {Object},  // (只读)当前模块的命名空间，如果无法定位，则为 null
     *    init:  {Boolean}, // (只读)是否正在初始化页面
     *    first: {Boolean}, // (只读)是否首次执行 authorized
     *    data:  {any}      // (读写)前述的 data 数据，或 data 函数返回的结果
     * }
     */
    $$(function (_) {
        var
            // 模块 UI 命名空间
            _ui = _mod.ui = _mod.ui || {},
            // 模块 API 命名空间
            _api = _mod.api,
            // 主工作区
            $main = $('.pt-main'),
            // 用户列表
            $users = $('#users');

        if (_.init) {
            // 检查指定的图片是否加载成功
            function imgOk(img) {
                if (!img.complete) {
                    return false;
                }

                if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) {
                    return false;
                }

                return true;
            }

            // 一个辅助函数，用于判断指定 id 的模块是否是公共模块
            function isPublicModule(id) {
                return (id == 'EeYoycXZXJ6INqReYNzHAA' || // 身份验证
                    id == 'EeY1g-7GCvCpNqReYNzHAA'); // 用户资料
            }

            // 在当前已经加载行数的基础上增加指定的行数
            function setLoadedSummary() {
                if (arguments.length < 1) {
                    return;
                }

                // 总行数和已加载行数
                var $loadedRows = $('#loaded-rows'),
                    $totalRows = $('#total-rows'),
                    totalRows = 0,
                    loadedRows = Long.fromString($loadedRows.text() || '0').add(arguments[0]);

                if (arguments.length == 1) {
                    // 此时认为只有提供了一个增量
                    totalRows = Long.fromString($totalRows.text() || '0').add(arguments[0]);
                } else {
                    // 第二个参数
                    totalRows = Long.fromValue(arguments[1]);
                }

                $loadedRows.text(loadedRows);
                $totalRows.text(totalRows);

                // 如果已经加载的行数等于或超过了总行数，隐藏加载更多按钮
                $('#load-more').css('display', loadedRows.gte(totalRows) ? 'none' : 'flex');
            }

            function cmpByPosition(x, y) {
                return x.position - y.position;
            }

            function sortByPosition(v) {
                $$.util.array.sort(v, cmpByPosition);
            }

            /*
             * User 结构如下：
             * {
             * }
             */
            _ui.user = {
                /*
                 * User 对象对应的 DOM HTML。
                 */
                get html() {
                    return '<article class="pt-row pt-model model-user">' +
                        '    <hr />' +
                        '    <header class="hover">' +
                        '        <div class="pt-row-icon">' +
                        '            <i class="material-icons lock-indicator">lock_outline</i>' +
                        '            <img class="model-user-face big" src="" alt="" />' +
                        '        </div>' +
                        '        <div class="pt-row-info">' +
                        '            <div>' +
                        '                <span class="pt-model-prop model-user-name"></span>' +
                        '                <span class="pt-model-prop model-user-login-name theme-text-2"></span>' +
                        '            </div>' +
                        '            <div class="w-5 hidden-phone">' +
                        '                <span class="pt-model-prop model-user-no"></span>' +
                        '            </div>' +
                        '            <div class="w-7 hidden-phone hidden-tablet"">' +
                        '                <span class="pt-model-prop model-user-mobile"></span>' +
                        '            </div>' +
                        '            <div class="w-13 hidden-phone hidden-tablet"">' +
                        '                <span class="pt-model-prop model-user-email"></span>' +
                        '            </div>' +
                        '            <div class="w-9 hidden-phone hidden-tablet"">' +
                        '                <span class="pt-model-prop model-user-create-time"></span>' +
                        '                <span class="pt-model-prop model-user-login-time theme-text-2"></span>' +
                        '            </div>' +
                        '        </div>' +
                        '        <div class="pt-row-more">' +
                        '            <button data-target-menu="#model-user-menu" class="mdc-ripple-surface mdc-ripple-surface--primary" data-mdc-ripple-is-unbounded data-mdc-auto-init="MDCRipple">' +
                        '                <i class="material-icons">more_vert</i>' +
                        '            </button>' +
                        '        </div>' +
                        '    </header>' +
                        '</article>';
                },

                /*
                 * 将指定的 App 对象添加到指定 DOM 列表的指定位置。
                 * 
                 * @param {any}    args   _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {Number} pos    插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                 * @param {jQuery} $list  要插入的 DOM 列表。
                 */
                insert: function (args, model, pos, $list) {
                    if (!model) {
                        // 没有提供 App 对象
                        return null;
                    }

                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = $users;
                    }

                    if (!$$.util.is.int(pos)) {
                        // 添加到列表最后
                        pos = -1;
                    }

                    // 目前位置上当前元素
                    var $next = pos >= 0 ? $list.children('.model-user').eq(pos) : null,
                        $model = null;

                    if ($next && $next.length) {
                        // 插入到目标元素之前
                        $model = $(_ui.user.html).insertBefore($next);
                    } else {
                        // 添加到列表最后
                        $model = $(_ui.user.html).appendTo($list);
                    }

                    // 将对象属性更新到目标元素
                    return _ui.user.update(args, model, $model, $list).mdcInit();
                },

                /*
                 * 将指定的 App 对象数组添加到指定 DOM 列表的指定位置。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} models 一个 App 对象的数组。
                 * @param {Number} pos   插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                 * @param {jQuery} $list 要插入的 DOM 列表。
                 */
                insertAll: function (args, models, pos, $list) {
                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = $users;
                    }

                    if (args.pageIndex === '1') {
                        // 清空现有列表
                        $list.empty();
                        // 添加到列表最后
                        pos = -1;
                    }

                    if (models && models.length) {
                        if (pos <= 0) {
                            // 添加到最前或最后
                            models.each(function (model) {
                                _ui.user.insert(args, model, pos, $list);
                            });
                        } else {
                            // 添加到指定位置
                            models.each(function (model, i) {
                                _ui.user.insert(args, model, pos + i, $list);
                            });
                        }

                        // 检查应用图标图片是否加载成功，如果不成功，则显示默认的图标
                        $list.find('img.model-user-face').one('error', function () {
                            var $img = $(this), $parent = $img.parent();
                            $img.remove();
                            $parent.append('<i class="material-icons big default-user-face">account_circle</i>');
                        });
                    }

                    return $list;
                },

                /*
                 * 将指定的 App 对象更新到现有的 DOM。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {jQuery} $model 现有的 DOM。
                 * @param {jQuery} $list 隶属的 DOM 列表。
                 */
                update: function (args, model, $model, $list) {
                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = $users;
                    }

                    if (!$model || !$model.length) {
                        // 没有提供 $model 时根据 model 或 args 查找目标元素
                        $model = $list.children('#model-user-' + model.id);
                    }

                    if (model && $model.length) {
                        var $h = $model
                            .attr('id', 'model-user-' + model.id)
                            .data('model', model)
                            .children('header'),
                            $face = $h.find('.model-user-face');

                        if ($face.length < 1) {
                            $h.find('.default-user-face').remove();
                            $face = $('<img class="model-user-face big" src="' + $$.web.url(model.faceUrl) + '" alt="" />').appendTo($h.children('.pt-row-icon'));
                        } else {
                            $face.attr('src', $$.web.url(model.faceUrl));
                        }

                        $h.find('.model-user-name').text(model.name);
                        $h.find('.model-user-login-name').text(model.loginName);
                        $h.find('.model-user-no').text(model.no);
                        $h.find('.model-user-mobile').text(model.mobile);
                        $h.find('.model-user-email').text(model.email);
                        $h.find('.model-user-create-time').text($$.util.fmt.day(model.createTime));
                        $h.find('.model-user-login-time').text($$.util.fmt.minute(model.loginTime));
                        $h.find('.lock-indicator').css('display', model.lockTime ? 'block' : 'none');
                    }

                    return $model;
                },

                /*
                 * 将指定的 App 对象对应的 DOM 元素从列表中移除。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {jQuery} $list 要从中移除元素的 DOM 列表。
                 */
                remove: function (args, model, $list) {
                    $('#model-user-' + args).remove();
                }
            };

            _ui.app = {
                /*
                 * App 对象对应的 DOM HTML。
                 */
                get html() {
                    return '<article class="pt-row pt-model model-app">' +
                        '    <hr />' +
                        '    <header class="hover">' +
                        '        <div class="pt-row-icon">' +
                        '            <img class="model-app-icon" src="../app.png" />' +
                        '        </div>' +
                        '        <div class="pt-row-info">' +
                        '            <div class="w-12">' +
                        '                <span class="pt-model-prop model-app-name"></span>' +
                        '            </div>' +
                        '            <div class="hidden-phone">' +
                        '                <span class="pt-model-prop model-app-description theme-text-2"></span>' +
                        '            </div>' +
                        '        </div>' +
                        '        <div class="pt-row-more">' +
                        '            <i class="material-icons">expand_more</i>' +
                        '        </div>' +
                        '    </header>' +
                        '    <section></section>' +
                        '</article>';
                },

                /*
                 * 将指定的 App 对象添加到指定 DOM 列表的指定位置。
                 * 
                 * @param {any}    args   _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {Number} pos    插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                 * @param {jQuery} $list  要插入的 DOM 列表。
                 */
                insert: function (args, model, pos, $list) {
                    if (!model) {
                        // 没有提供 App 对象
                        return null;
                    }

                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = $users;
                    }

                    if (!$$.util.is.int(pos)) {
                        // 添加到列表最后
                        pos = -1;
                    }

                    // 目前位置上当前元素
                    var $next = pos >= 0 ? $list.children('.model-app').eq(pos) : null,
                        $model = null;

                    if ($next && $next.length) {
                        // 插入到目标元素之前
                        $model = $(_ui.app.html).insertBefore($next);
                    } else {
                        // 添加到列表最后
                        $model = $(_ui.app.html).appendTo($list);
                    }

                    // 将对象属性更新到目标元素
                    return _ui.app.update(args, model, $model, $list).mdcInit();
                },

                /*
                 * 将指定的 App 对象数组添加到指定 DOM 列表的指定位置。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} models 一个 App 对象的数组。
                 * @param {Number} pos   插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                 * @param {jQuery} $list 要插入的 DOM 列表。
                 */
                insertAll: function (args, models, pos, $list) {
                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = $('#apps');
                    }

                    if (!$$.util.is.int(pos)) {
                        // 清空现有列表
                        $list.empty();
                        // 添加到列表最后
                        pos = -1;
                    }

                    if (models && models.length) {
                        if (pos <= 0) {
                            // 添加到最前或最后
                            models.each(function (model) {
                                _ui.app.insert(args, model, pos, $list);
                            });
                        } else {
                            // 添加到指定位置
                            models.each(function (model, i) {
                                _ui.app.insert(args, model, pos + i, $list);
                            });
                        }

                        // 检查应用图标图片是否加载成功，如果不成功，则显示默认的图标
                        $list.find('img.model-app-icon').one('error', function () {
                            this.parentElement.innerHTML = '<i class="material-icons">crop_original</i>';
                        });

                        $('.model-app').on('children', function (evt) {
                            $$.ui.msg = '...';
                            _api.modules
                                // 传递应用的 id
                                .one('args', function (e) {
                                    e.args = {
                                        // 引用的 id
                                        appId: evt.model.id,
                                        // 当前用户的 id
                                        roleId: args.id
                                    };
                                })
                                .one('success', function (e) {
                                    sortByPosition(e.result);
                                    _ui.module.insertAll(e.args, e.result, -1, $('#model-app-' + e.args.appId + '>section'));
                                })
                                .one('load', function () {
                                    evt.childrenLoaded = true;
                                    $$.ui.msg = '';
                                })();
                        });
                    }

                    return $list;
                },

                /*
                 * 将指定的 App 对象更新到现有的 DOM。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {jQuery} $model 现有的 DOM。
                 * @param {jQuery} $list 隶属的 DOM 列表。
                 */
                update: function (args, model, $model, $list) {
                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = $users;
                    }

                    if (!$model || !$model.length) {
                        // 没有提供 $model 时根据 model 或 args 查找目标元素
                        $model = $list.children('#model-app-' + model.id);
                    }

                    if (model && $model.length) {
                        var $h = $model
                            .attr('id', 'model-app-' + model.id)
                            .data('model', model)
                            .children('header');

                        $h.find('.model-app-icon').attr('src', $$.web.url('~/com/' + model.developerCode.toLowerCase() + '/' + model.identifier.toLowerCase() + '/app.png'));
                        $h.find('.model-app-name').text(model.name);
                        $h.find('.model-app-description').text(model.description);
                    }

                    return $model;
                }
            };

            _ui.module = {
                /*
                 * Module 对象对应的 DOM HTML。
                 */
                get html() {
                    return '<article class="pt-row pt-model model-module">' +
                        '    <hr />' +
                        '    <header class="hover">' +
                        '        <div class="pt-row-icon">' +
                        '            <i class="pt-row-toggle material-icons mdc-ripple-surface mdc-ripple-surface--primary mdc-theme--primary" data-mdc-ripple-is-unbounded data-mdc-auto-init="MDCRipple">check_box_outline_blank</i>' +
                        '        </div>' +
                        '        <div class="pt-row-info">' +
                        '            <div class="w-8">' +
                        '                <span class="pt-model-prop model-module-name"></span>' +
                        '            </div>' +
                        '            <div>' +
                        '                <span class="pt-model-prop model-module-description theme-text-2"></span>' +
                        '            </div>' +
                        '        </div>' +
                        '    </header>' +
                        '</article>';
                },

                /*
                 * 将指定的 App 对象添加到指定 DOM 列表的指定位置。
                 * 
                 * @param {any}    args   _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {Number} pos    插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                 * @param {jQuery} $list  要插入的 DOM 列表。
                 */
                insert: function (args, model, pos, $list) {
                    if (!model) {
                        // 没有提供 App 对象
                        return null;
                    }

                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = $users;
                    }

                    if (!$$.util.is.int(pos)) {
                        // 添加到列表最后
                        pos = -1;
                    }

                    // 目前位置上当前元素
                    var $next = pos >= 0 ? $list.children('.model-module').eq(pos) : null,
                        $model = null;

                    if ($next && $next.length) {
                        // 插入到目标元素之前
                        $model = $(_ui.module.html).insertBefore($next);
                    } else {
                        // 添加到列表最后
                        $model = $(_ui.module.html).appendTo($list);
                    }

                    // 将对象属性更新到目标元素
                    return _ui.module.update(args, model, $model, $list).mdcInit();
                },

                /*
                 * 将指定的 App 对象数组添加到指定 DOM 列表的指定位置。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} models 一个 App 对象的数组。
                 * @param {Number} pos   插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                 * @param {jQuery} $list 要插入的 DOM 列表。
                 */
                insertAll: function (args, models, pos, $list) {
                    if (!$$.util.is.int(pos)) {
                        // 清空现有列表
                        $list.empty();
                        // 添加到列表最后
                        pos = -1;
                    }

                    if (models && models.length) {
                        if (pos <= 0) {
                            // 添加到最前或最后
                            models.each(function (model) {
                                _ui.module.insert(args, model, pos, $list);
                            });
                        } else {
                            // 添加到指定位置
                            models.each(function (model, i) {
                                _ui.module.insert(args, model, pos + i, $list);
                            });
                        }
                    }

                    return $list;
                },

                /*
                 * 将指定的 App 对象更新到现有的 DOM。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {jQuery} $model 现有的 DOM。
                 * @param {jQuery} $list 隶属的 DOM 列表。
                 */
                update: function (args, model, $model, $list) {
                    if (!$model || !$model.length) {
                        // 没有提供 $model 时根据 model 或 args 查找目标元素
                        $model = $list.children('#model-module-' + model.id);
                    }

                    if (model && $model.length) {
                        var $h = $model
                            .attr('id', 'model-module-' + model.id)
                            .data('model', model)
                            .children('header');

                        $h.find('.model-module-name').text(model.name);
                        $h.find('.model-module-description').text(model.description);

                        if (isPublicModule(model.id)) {
                            // 公共模块不应该做选择
                            $model.rowSelected(true);
                            $h.find('.pt-row-toggle').addClass('disabled');
                        } else {
                            $model.rowSelected(!!model.grantTime);
                            $h.find('.pt-row-toggle').removeClass('disabled');
                        }
                    }

                    return $model;
                }
            };

            // list 操作事件
            _api.list
                .on('args', function (e) {
                    e.args = {
                        pageIndex: $('#list-page-index').val(), // 页码
                        orderName: $('#list-order-name').val(), // 排序名称
                        orderDirection: $('#list-order-direction').val(), // 排序方向
                        name: $('#list-name').val() // 用户名称
                    };
                })
                .on('success', function (e) {
                    // 显示列表
                    _ui.user.insertAll(e.args, e.result.users);

                    if (e.args.pageIndex == '1') {
                        $('#loaded-rows').text('0');
                    }

                    // 总行数和已加载行数
                    setLoadedSummary(e.result.users.length, e.result.totalRows);
                })
                .on('load', function () {
                    $$.ui.msg = '';
                });

            _api.add
                .on('args', function (e) {
                    e.args = {
                        loginName: $('#add-login-name').val(),
                        password: $('#add-password').val(),
                        name: $('#add-name').val(),
                        no: $('#add-no').val(),
                        mobile: $('#add-mobile').val(),
                        email: $('#add-email').val(),
                        loginHomeUrl: $('#add-login-home-url').val()
                    };
                })
                .on('success', function (e) {
                    // 将新用户添加到列表最前面
                    _ui.user.insert(e.args, e.result, 0);
                    setLoadedSummary(1);

                    // 检查应用图标图片是否加载成功，如果不成功，则显示默认的图标
                    $('#model-user-' + e.result.id).find('>header img.model-user-face').one('error', function () {
                        var $img = $(this), $parent = $img.parent();
                        $img.remove();
                        $parent.append('<i class="material-icons big">account_circle</i>');
                    });

                    // 重置对话框
                    $('#add-login-name').val('');
                    $('#add-password').val('');
                    $('#add-name').val('');
                    $('#add-no').val('');
                    $('#add-mobile').val('');
                    $('#add-email').val('');
                    $('#add-login-home-url').val('');
                });

            $('#add-dialog').on('ok', function (e) {
                $$.ui.msg = '...';
                _api.add
                    .one('load', function () {
                        $$.ui.msg = '';
                        e.done = true;
                    })();
            });

            // 锁定操作事件
            _api.lock
                .on('load', function (e) {
                    $$.ui.msg = '';
                });

            // 删除操作事件
            _api.delete
                .on('success', function (e) {
                    _ui.user.remove(e.args);
                    setLoadedSummary(-1);
                })
                .on('load', function (e) {
                    $$.ui.msg = '';
                });

            // 排序方向
            $('.pt-order-field').on('click', function (e) {
                e.preventDefault();

                var
                    // 点击的排序字段
                    $me = $(this),
                    // 排序字段上定义的排序方向
                    dir = ($me.attr('data-order-direction') || 'asc').toLowerCase(),
                    // 排序字段上定义的排序名称，如果没有提供，则按默认排序名称排序
                    name = ($me.attr('data-order-name') || '').toLowerCase();

                // 反转排序方向
                dir = dir == 'asc' ? 'desc' : 'asc';
                // 设置排序方向指示图标
                $me.attr('data-order-direction', dir)
                    .children('.material-icons').text('arrow_drop_' + (dir == 'desc' ? 'up' : 'down'));

                // 设置排序条件
                $('#list-order-name').val(name);
                $('#list-order-direction').val(dir);

                // 重置页码
                $('#list-page-index').val(1);
                // 重新加载列表
                $$.ui.msg = '...';
                _api.list();
            });

            // 加载更多
            $('#load-more').on('click', function () {
                var $pi = $('#list-page-index'),
                    pageIndex = Long.fromValue($pi.val()).add(1);

                $pi.val(pageIndex);

                $$.ui.msg = '...';
                _api.list();
            });

            // 搜索
            $('#search').on('click', function () {
                // 重置页码
                $('#list-page-index').val(1);

                // 重新加载列表
                $$.ui.msg = '...';
                _api.list();
            });

            // 菜单
            $('#model-user-menu')
                .on('opening', function (e) {
                    var user = e.model,
                        items = e.items,
                        isSelf = user.id === _.user.id,
                        $lockItem = $(items[4]),
                        $deleteItem = $(items[5]);

                    // 已经被锁定，显示解锁菜单，尚未被锁定，显示锁定菜单
                    $lockItem
                        .children('i').text(user.lockTime ? 'lock_open' : 'lock_outline')
                        .next().text(user.lockTime ? '解锁' : '锁定');

                    // 如果用户选中了自己，则不能被删除或锁定
                    $lockItem.toggleClass('disabled', isSelf);
                    // 已经登录的用户不能被删除
                    $deleteItem.toggleClass('disabled', isSelf || !!user.loginTime);
                })
                .on('selected', function (selectedEvt) {
                    var user = selectedEvt.model;
                    switch (selectedEvt.selectedIndex) {
                        case 4:
                            // 锁定或解锁
                            $$.ui.msg = '...';
                            _api.lock
                                .one('args', function (e) {
                                    e.args = {
                                        id: user.id,
                                        locked: !!!user.lockTime
                                    };
                                })

                                .one('success', function (e) {
                                    user.lockTime = e.result.lockTime;
                                    $('#model-user-' + user.id + '>header .lock-indicator').css('display', user.lockTime ? 'block' : 'none');
                                })();
                            break;
                        case 5:
                            // 删除
                            $$.ui.confirm('确认删除', '您确实要删除用户 ' + user.name + '(' + user.loginName + ') 么？用户资料将被彻底删除，并且无法恢复！', function () {
                                $$.ui.msg = '...';
                                _api.delete
                                    .one('args', function (e) {
                                        e.args = user.id;
                                    })();
                            });
                            break;
                        default:
                            break;
                    }
                });

            // 设置资料
            $('#edit-dialog')
                // 对话框即将打开
                .on('opening', function (e) {
                    $('#edit-login-name').val(e.model.loginName);
                    $('#edit-name').val(e.model.name);
                    $('#edit-no').val(e.model.no);
                    $('#edit-mobile').val(e.model.mobile);
                    $('#edit-email').val(e.model.email);
                    $('#edit-login-home-url').val(e.model.loginHomeUrl);
                })
                // 点击了对话框的确定按钮
                .on('ok', function (okEvt) {
                    // 显示进度动画
                    $$.ui.msg = '...';
                    _api.edit
                        // 设置请求参数
                        .one('args', function (e) {
                            e.args = {
                                id: okEvt.model.id,
                                loginName: $('#edit-login-name').val(),
                                name: $('#edit-name').val(),
                                no: $('#edit-no').val(),
                                mobile: $('#edit-mobile').val(),
                                email: $('#edit-email').val(),
                                loginHomeUrl: $('#edit-login-home-url').val()
                            };
                        })
                        // 在提交前检查数据是否实际发生改变
                        .one('before', function (e) {
                            // 如果前后数据没有发生变化，则不需要提交到服务器
                            e.cancel =
                                okEvt.model.loginName == e.args.loginName &&
                                okEvt.model.name == e.args.name &&
                                okEvt.model.no == e.args.no &&
                                okEvt.model.mobile == e.args.mobile &&
                                okEvt.model.email == e.args.email &&
                                okEvt.model.loginHomeUrl == e.args.loginHomeUrl;
                        })
                        // 请求成功时更新的 UI
                        .one('success', function (e) {
                            // 将返回结果更新到 UI
                            _ui.user.update(e.args, e.result);

                            if (e.result.id == _.user.id) {
                                // 当前用户
                                _.user.loginName = e.result.loginName;
                                _.user.name = e.result.name;
                                _.user.no = e.result.no;
                                _.user.mobile = e.result.mobile;
                                _.user.email = e.result.email;
                                _.user.loginHomeUrl = e.result.loginHomeUrl;

                                $('.pt-nav-toolbar>a>b').text(_.user.name);
                            }
                        })
                        // 取消请求或请求成功时关闭对话框和进度动画
                        .one('load', function (e) {
                            // 关闭对话框
                            okEvt.done = true;
                            // 隐藏进度动画
                            $$.ui.msg = '';
                        })();
                });

            // 设置密码
            $('#set-password-dialog')
                .on('opening', function (e) {
                    $('#set-password-dialog-title').text(e.model.name + '(' + e.model.loginName + ')');
                })
                // 点击了对话框的确定按钮
                .on('ok', function (okEvt) {
                    // 显示进度动画
                    $$.ui.msg = '...';
                    _api.setPassword
                        // 设置请求参数
                        .one('args', function (e) {
                            e.args = {
                                id: okEvt.model.id,
                                password: $('#set-password-password').val()
                            };
                        })
                        // 取消请求或请求成功时关闭对话框和进度动画
                        .one('load', function (e) {
                            // 关闭对话框
                            okEvt.done = true;
                            // 隐藏进度动画
                            $$.ui.msg = '';
                        })();
                });
            
            _api.apps
                .on('before', function (e) {
                    e.cancel = !!$('#apps').data('loaded');
                })
                .on('success', function (e) {
                    sortByPosition(e.result);
                    _ui.app.insertAll(e.args, e.result);
                    $('#apps').data('loaded', true);
                })
                .on('load', function () {
                    // 折叠所有行，清空每一个应用下面的模块列表
                    $('.model-app').each(function () {
                        $(this).rowExpanded(false, true);
                    });
                    $$.ui.msg = '';
                });

            // 设置权限
            $('#apps-dialog')
                .on('opening', function (openingEvt) {
                    $('#apps-dialog-title').text(openingEvt.model.name + '(' + openingEvt.model.loginName + ')');

                    $('#apps-dialog').data('model', openingEvt.model);
                    $$.ui.msg = '...';
                    // 加载 app 列表
                    _api.apps.one('args', function (e) {
                        e.args = openingEvt.model;
                    })();
                });

            $('#apps').on('afterselect', '.model-module', function (e) {
                if (isPublicModule(e.model.id)) {
                    return;
                }

                var user = $('#apps-dialog').data('model');
                $$.ui.msg = '...';

                if (e.selected) {
                    // 授权
                    _api.grant
                        .one('args', function (argsEvt) {
                            argsEvt.args = {
                                moduleId: e.model.id,
                                roleId: user.id
                            };
                        })
                        .one('load', function (loadEvt) {
                            $$.ui.msg = '';
                        })();
                } else {
                    // 取消授权
                    _api.revoke
                        .one('args', function (argsEvt) {
                            argsEvt.args = {
                                moduleId: e.model.id,
                                roleId: user.id
                            };
                        })
                        .one('load', function (loadEvt) {
                            $$.ui.msg = '';
                        })();
                }
            });

            // 上传头像
            var progress = null,
                $file = $('#set-face-file');

            // 为 setFace 注册事件
            _api.setFace
                // 获取文件列表
                .on('files', function (e) {
                    // 只上传第一个文件
                    e.files = $file[0].files;
                })

                // 上传进度
                .on('progress', function (e) {
                    progress.progress = e.percent / 100;
                });

            // 设置头像
            $('#set-face-dialog')
                .on('opening', function (e) {
                    if (!progress) {
                        progress = mdc.linearProgress.MDCLinearProgress.attachTo(document.getElementById('set-face-progress'));
                    }

                    progress.progress = 0;

                    $('#set-face-thumb').attr('src', $$.web.url(e.model.faceUrl));
                    $('#set-face-dialog-title').text(e.model.name + '(' + e.model.loginName + ')');
                })
                .on('ok', function (okEvt) {
                    _api.setFace
                        // POST 操作的 data
                        .on('data', function (e) {
                            var url = e.files[0].url;
                            e.data = {
                                id: okEvt.model.id,
                                // 保存时添加一个根路径前缀
                                faceUrl: url.startsWith('~') ? url : ('~' + url)
                            };
                        })
                        // 当设置成功后关闭对话框，刷新导航和当前列表
                        .one('success', function (e) {
                            progress.progress = 1;

                            if (okEvt.model.id == _.user.id) {
                                _.user.faceUrl = e.data.faceUrl;
                                // 当前用户，更新导航中的用户头像
                                $('.pt-nav-userbar>a')
                                    .html('<img src="' + $$.web.url(_.user.faceUrl) + '" alt="" /><b></b>')
                                    .children('img').one('error', function () {
                                        $('.pt-nav-userbar>a').html('<i class="material-icons">account_circle</i><b></b>');
                                        // 用户名称
                                        $('.pt-nav-userbar>a>b').text(_.user.name);
                                    });

                                $('.pt-nav-userbar>a>b').text(_.user.name);
                            }

                            okEvt.model.faceUrl = e.data.faceUrl;
                            _ui.user.update(e.args, okEvt.model);
                        })
                        .one('load', function () {
                            // 关闭对话框
                            okEvt.done = true;
                        })();
                });

            // 选择文件
            $('#set-face-select-file').on('click', function () {
                $file.trigger('click');
            });

            // 预览文件
            $file.on('change', function () {
                var files = $file[0].files,
                    $btnUpload = $('#set-face-dialog button[data-ok]').prop('disabled', true);
                if (!files.length) {
                    $$.ui.msg = "请选择一张图片。";
                    return;
                }

                if (!/^image\//.test(files[0].type)) {
                    $$.ui.msg = "文件不是有效图片。";
                    return;
                }

                // 缩略图
                (function (file) {
                    var reader = new FileReader();
                    reader.onload = (function (img) {
                        return function (e) {
                            img.src = e.target.result;
                        };
                    })($("#set-face-thumb")[0]);

                    reader.readAsDataURL(file);
                })(files[0]);

                // 上传按钮状态
                (function (file) {
                    // 文件不能超过 500KB
                    if (file.size > 512000) {
                        $$.ui.msg = "图片文件超过 500KB (" + (file.size / 1024).toFixed(2) + "KB)。";
                    } else {
                        $$.ui.msg = '';
                        $btnUpload.prop('disabled', false);
                    }
                })(files[0]);
            });

            // 初始化 mdc
            $main.mdcInit();
        }

        // 加载用户列表
        _api.list();
    });
})(jQuery, pittypat, pittypat.namespace('waln.authority.users'));
